#include "ScientificCalculation.h"
#include <iostream>

void ScientificCalculation::dataprocess() {
    while (!done) {
        DataResult item;
        if(dataprocess_queue.try_pop(item)) {
            if (item.original_data < 0) item.original_data = -item.original_data;
            calculate_queue.push(item);
        } else {
            std::this_thread::sleep_for(std::chrono::milliseconds(10)); // Avoid busy waiting
        }
    }
}

void ScientificCalculation::calculate() {
    while (!done) {
        DataResult item;
        if(calculate_queue.try_pop(item)) {
            item.original_data = static_cast<int>(item.original_data);
            item.result = (static_cast<int>(item.original_data) * 3) % 2 == 0;
            final_results.push(item);
        } else {
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
}

void ScientificCalculation::results_analysis() {
    while (!done) {
        DataResult item;
        if(final_results.try_pop(item)) {
            std::lock_guard<std::mutex> lock(results_mutex);
            results_map[item.original_data] = item.result;
            if (--task_counter == 0) {
                cv.notify_all();
            }
        } else {
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
}

void ScientificCalculation::init() {
    threads.emplace_back(&ScientificCalculation::dataprocess, this);
    threads.emplace_back(&ScientificCalculation::calculate, this);
    for(int i = 0; i < 3; ++i) {
        threads.emplace_back(&ScientificCalculation::results_analysis, this);
    }
}

std::unordered_map<double, bool> ScientificCalculation::inference(const std::vector<double>& inputs) {
    // 清空results_map和重置task_counter
    {
        std::lock_guard<std::mutex> lock(results_mutex);
        results_map.clear();
        task_counter = 0;
    }

    for(auto& input : inputs) {
        dataprocess_queue.push({input, false});
        task_counter++;
    }

    // 等待所有任务完成
    wait_for_completion();

    // 返回结果
    std::unordered_map<double, bool> local_results;
    {
        std::lock_guard<std::mutex> lock(results_mutex);
        local_results = results_map;
    }

    return local_results;
}

void ScientificCalculation::wait_for_completion() {
    std::unique_lock<std::mutex> lock(results_mutex);
    cv.wait(lock, [this]{ return this->task_counter == 0; });
}

ScientificCalculation::ScientificCalculation() {}

ScientificCalculation::~ScientificCalculation() {
    done = true;
    dataprocess_queue.notify_all();
    calculate_queue.notify_all();
    final_results.notify_all();
    for(auto& t : threads) {
        if(t.joinable()) {
            t.join();
        }
    }
}
